package com.qqn.acknowledge.reflection;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/*
 总结：采用这种设计，我们可以看到：对象的实例化和方法的调用不再依赖于硬编码的类名和方法名，而是基于字符串
        和注解所提供的配置信息进行，这使得代码非常的灵活且通用，特别适用于编写需要高度解构的框架和应用程序。
        当然在实际框架中，所采用的方法要复杂和安全的多，涉及不同的工作流程，策略以及优化措施，本示例的目的主要是
        帮助理解反射的应用场景。虽然反射为程序设计带来了极大的灵活性和功能性，但它也带来了一些挑战，包括性能开销、
        安全性问题和维护的复杂性，因此设计者在使用反射时必须谨慎，以便在灵活性和这些潜在的问题之间找到平衡点。
        在常规的应用程序级别编程中，通常更推荐直接使用具体的类和方法，这样有助于保持代码的可读性和提高运行性能。
 */
/**
 * @ClassName: ReflectVisit
 * @Description: ReflectVisit
 * @Author: 刘神仙
 * @Date: 2025-03-25 21:15
 */
public class ReflectVisit4 {
    public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        // String className = "com.qqn.acknowledge.reflection.Order";
        // String fieldName = "customer";
        String className = "com.qqn.acknowledge.reflection.User";
        String fieldName = "message";
        Container container = new Container();
        container.init();
        // clazz 是 Class对象，Class对象表示的是类的元信息（即类的结构定义，加上类型就是指 哪个类的原信息），并不是类的具体实例
        // 如果需要创建类的实例，可以通过 Class 对象的 newInstance() 方法(已过时) 或使用反射获取构造器并调用Constructor.newInstance() 方法。
        // Class<?> clazz = Class.forName("com.qqn.acknowledge.reflection.Customer");
        // Object obj = container.getServiceInstanceByClass(clazz);
        // System.out.println(obj);

        Class<?> clazz1 = Class.forName(className);
        Object obj = container.createInstance(clazz1); // 得到的是带参的 Order 实例
        Field field = clazz1.getDeclaredField(fieldName);// 返回的是一个 Field 对象，该对象包含了 Order 类中 customer 字段的元信息
        field.setAccessible(true);
        Object fieldValue = field.get(obj); // 使用 field.get(obj) 方法获取 obj 对象中 customer 字段的值
        System.out.println(fieldValue);
        /*
        field.get(obj) 方法用于从 obj 对象中获取 customer 字段的实际值。
        obj 是 Order 类的实例，field 是 Order 类中 customer 字段的元信息。
        field.get(obj) 返回的是 obj 对象中 customer 字段的实际值。
         */
        Method[] methods = fieldValue.getClass().getDeclaredMethods();
        for (Method method : methods) {
            if (method.getDeclaredAnnotation(Printable.class) != null) {
                method.invoke(fieldValue);
            }
        }
    }
}
